;;; +tab9.el --- config -*- lexical-binding: t -*-

;;; Commentary:

;; Configure for tabnine, connot download binary.

;;; Code:

;; -------- company-tab9 --------
(use-package company-tabnine
  :after company
  :if (executable-find "TabNine")
  :init
  ;; uncomment below: Symbol’s value as variable is void: company-backends
  (add-to-list 'company-backends #'company-tabnine)
  ;; Trigger completion immediately.
  (setq company-idle-delay 0)
  ;; Number the candidates (use M-1, M-2 etc to select completions).
  (setq company-show-quick-access t)
  ;; Use the tab-and-go frontend.
  ;; Allows TAB to select and complete at the same time.
  (company-tng-mode)
  (setq company-frontends
        '(company-tng-frontend
          company-pseudo-tooltip-frontend
          company-echo-metadata-frontend))
  ;; The free version of TabNine is good enough,
  ;; and below code is recommended that TabNine not always
  ;; prompt me to purchase a paid version in a large project.
  (defadvice company-echo-show (around disable-tabnine-upgrade-message activate)
    (let ((company-message-func (ad-get-arg 0)))
      (when (and company-message-func
                 (stringp (funcall company-message-func)))
        (unless (string-match "The free version of TabNine only indexes up to" (funcall company-message-func))
          ad-do-it))))
  :config
  ;; calling tab9 & lsp simultaneously
  ;; via: emacs-china.org/t/tabnine/9988/40
  (defun p1uxtar-company-sort-add-tabnine (candidates)
    (if (or (functionp company-backend)
	        (not (and (listp company-backend) (memq 'company-tabnine company-backend))))
	    candidates
      (let ((candidates-table (make-hash-table :test #'equal))
	        candidates-1
	        candidates-2)
	    (dolist (candidate candidates)
	      (if (eq (get-text-property 0 'company-backend candidate)
		          'company-tabnine)
	          (unless (gethash candidate candidates-table)
		        (push candidate candidates-2))
	        (push candidate candidates-1)
	        (puthash candidate t candidates-table)))
	    (setq candidates-1 (nreverse candidates-1))
	    (setq candidates-2 (nreverse candidates-2))
	    (nconc (seq-take candidates-1 2)
	           (seq-take candidates-2 2)
	           (seq-drop candidates-1 2)
	           (seq-drop candidates-2 2)))))
  (add-to-list 'company-transformers 'p1uxtar-company-sort-add-tabnine t)
  ;; :bind
  ;; (:map company-active-map
  ;;       ("<tab>" . 'company-complete-common-or-cycle)
  ;;       ("RET" . 'company-complete-selection)
  ;;       ("C-n" . 'company-select-next)
  ;;       ("C-p" . 'company-select-previous))
  ;; custom TabNine path:
  ;; (setq company-tabnine-binaries-folder "~/.emacs.d/.TabNine")
  ;; workaround for company-transformers
  (setq company-tabnine--disable-next-transform nil)
  (defun my-company--transform-candidates (func &rest args)
    (if (not company-tabnine--disable-next-transform)
        (apply func args)
      (setq company-tabnine--disable-next-transform nil)
      (car args)))
  (defun my-company-tabnine (func &rest args)
    (when (eq (car args) 'candidates)
      (setq company-tabnine--disable-next-transform t))
    (apply func args))
  (advice-add #'company--transform-candidates :around #'my-company--transform-candidates)
  (advice-add #'company-tabnine :around #'my-company-tabnine))

(provide '+tab9)

;;; +tab9.el ends here
